package com.yuanqiworld.vw.web;

import com.yuanqiworld.vw.domain.Metadata;
import com.yuanqiworld.vw.domain.UnityModel;
import com.yuanqiworld.vw.service.ApplicationConfig;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import java.util.Date;
import java.util.ResourceBundle;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.spi.LoggerRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.roo.addon.web.mvc.controller.finder.RooWebFinder;
import org.springframework.roo.addon.web.mvc.controller.json.RooWebJson;
import org.springframework.roo.addon.web.mvc.controller.scaffold.RooWebScaffold;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

@RequestMapping("/unitymodels")
@Controller
@RooWebFinder
@RooWebScaffold(path = "unitymodels", formBackingObject = UnityModel.class)
@RooWebJson(jsonObject = UnityModel.class)
public class UnityModelController {

    private static final Logger LOGGER = LoggerFactory.getLogger(UnityModelController.class);

    private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle("app");

    @Autowired
    private ApplicationConfig applicationConfig;

    @RequestMapping(params = "find=LastFileByModelName", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<org.springframework.core.io.Resource> findLastUnityModelFileByModelName(@RequestParam("modelName") String modelName) {
        UnityModel unityModel = UnityModel.findUnityModelsByModelName(modelName).getSingleResult();
        FileSystemResource resource = new FileSystemResource(applicationConfig.findModelFilename(unityModel.getModelFilename()));
        return new ResponseEntity<Resource>(resource, HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.POST, produces = "text/html")
    public String create(@Valid UnityModel unityModel, @RequestParam("modelFile") MultipartFile modelFile, @RequestParam("previewFile") MultipartFile previewFile, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
        if (bindingResult.hasErrors()) {
            populateEditForm(uiModel, unityModel);
            return "unitymodels/create";
        }
        uiModel.asMap().clear();
        unityModel.setUploadDatetime(new Date());
        unityModel.setModelVersion(UnityModel.findMaxVersionByModelName(unityModel.getModelName()) + 1);
        if (!saveModelFile(unityModel, modelFile)) {
            return null;
        }
        if (!savePreviewFile(unityModel, previewFile)) {
            unityModel.setUploadPreview(null);
            unityModel.setPreviewFilename(null);
            unityModel.setPreviewSize(null);
        }
        unityModel.persist();
        return "redirect:/unitymodels/" + encodeUrlPathSegment(unityModel.getId().toString(), httpServletRequest);
    }

    private boolean savePreviewFile(UnityModel unityModel, MultipartFile previewFile) {
        if (previewFile != null) {
            String previewExtension = (previewFile == null) ? null : FilenameUtils.getExtension(previewFile.getOriginalFilename());
            unityModel.setUploadPreview(previewFile.getOriginalFilename());
            unityModel.setPreviewFilename(unityModel.getModelName() + "-" + unityModel.getModelVersion() + "-preview." + previewExtension);
            unityModel.setPreviewSize(previewFile.getSize());
        }
        if (previewFile != null) {
            InputStream previewFileInputStream = null;
            FileOutputStream previewFileOutputStream = null;
            try {
                previewFileInputStream = previewFile.getInputStream();
                previewFileOutputStream = new FileOutputStream(applicationConfig.findPreviewFilename(unityModel.getPreviewFilename()));
                IOUtils.copy(previewFileInputStream, previewFileOutputStream);
            } catch (IOException e) {
                LOGGER.warn(RESOURCE_BUNDLE.getString("file.save.failure"), e);
                return false;
            } finally {
                if (previewFileInputStream != null) IOUtils.closeQuietly(previewFileInputStream);
                if (previewFileOutputStream != null) IOUtils.closeQuietly(previewFileOutputStream);
            }
        }
        return true;
    }

    private boolean saveModelFile(UnityModel unityModel, MultipartFile modelFile) {
        String modelExtension = FilenameUtils.getExtension(modelFile.getOriginalFilename());
        unityModel.setUploadModel(modelFile.getOriginalFilename());
        unityModel.setModelFilename(unityModel.getModelName() + "-" + unityModel.getModelVersion() + "." + modelExtension);
        unityModel.setModelSize(modelFile.getSize());
        InputStream modelFileInputStream = null;
        FileOutputStream modelFileOutputStream = null;
        try {
            modelFileInputStream = modelFile.getInputStream();
            modelFileOutputStream = new FileOutputStream(applicationConfig.findModelFilename(unityModel.getModelFilename()));
            IOUtils.copy(modelFileInputStream, modelFileOutputStream);
        } catch (IOException e) {
            LOGGER.warn(RESOURCE_BUNDLE.getString("file.save.failure"), e);
            return false;
        } finally {
            if (modelFileInputStream != null) IOUtils.closeQuietly(modelFileInputStream);
            if (modelFileOutputStream != null) IOUtils.closeQuietly(modelFileOutputStream);
        }
        return true;
    }

    void populateEditForm(Model uiModel, UnityModel unityModel) {
        uiModel.addAttribute("unityModel", unityModel);
        uiModel.addAttribute("modelTypes", Metadata.findMetadatasByCategory("MODEL_TYPE").getResultList());
        addDateTimeFormatPatterns(uiModel);
    }
}
